package com.regan.erp.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.google.common.collect.Lists;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;
import com.regan.erp.exception.MyBaselogicException;
import org.apache.poi.ss.usermodel.*;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.stream.Stream;

/**
 * excel工具类，对hutool进行excel工具类 再次封装
 *
 * @author zhangby
 * @date 2018/4/8 下午1:18
 */
public class ExcelUtils {

    /** >>>>>>>>>>>>>>>>>>>> 导出 <<<<<<<<<<<<<<<<<<< */

    /**
     * excel 导出
     *
     * @param list 导出数据
     * @param key  excel导出的列名，已经对应的key -> "name:姓名,age:年龄"
     * @param function <参数1：colums(record 列表)，参数2：record，参数3：列表结果>
     */
    public static File export(List<Record> list, String key, File file, BiFunction<Record,String,String> function) {
        List<String> header; //excel head
        List<String> colums; //reacord -> coloums
        try {
            //获取头部信息
            colums = FunctionUtils.convers(CommonUtil.splitStr(key, ","), str -> CommonUtil.splitStr4Temp(str, "{}:{}").get(0));
            header = FunctionUtils.convers(CommonUtil.splitStr(key, ","), str -> CommonUtil.splitStr4Temp(str, "{}:{}").get(1));
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyBaselogicException("999", "excel导出异常，列名获取出错");
        }

        //数据转换
        List<List<String>> convers = FunctionUtils.convers(list, record -> {
            List<String> li = Lists.newArrayList();
            //数据处理回调
            if (ObjectUtil.isNotNull(function)) {
                List<String> rsList = Lists.newArrayList();
                if (ObjectUtil.isNotNull(colums) && !colums.isEmpty()) {
                    colums.forEach(c->{
                        String apply = function.apply(record, c);
                        rsList.add(apply);
                    });
                    li = rsList;
                } else {
                    Lists.newArrayList(record.getColumnNames()).forEach(c->{
                        String apply = function.apply(record, c);
                        rsList.add(apply);
                    });
                    li = rsList;
                }
            } else {
                List<String> rsList = Lists.newArrayList();
                if (ObjectUtil.isNotNull(colums) && !colums.isEmpty()) {
                    colums.forEach(colum -> rsList.add(Convert.convert(String.class, record.get(colum))));
                    li = rsList;
                } else {
                    Stream.of(record.getColumnNames()).forEach(colum -> rsList.add(record.get(colum)));
                }
            }
            return li;
        });

        //添加头部信息
        if (ObjectUtil.isNotNull(header)) {
            convers.add(0,header);
        }

        //校验文件是否存在
        try {
            //判断文件夹是否存在
            String path = file.getPath();
            String pathSub = path.substring(0, path.lastIndexOf("/")>0?path.lastIndexOf("/"):path.lastIndexOf("\\"));
            File folder=new File(pathSub);
            if(!folder.exists()){
                folder.mkdirs();
            }
            //判断文件是否存在
            if(!file.exists()){
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new MyBaselogicException("999", "excel导出异常，文件创建失败");
        }

        //创建excel
        ExcelWriter writer = ExcelUtil.getWriter(file.getPath());
        writer.write(convers);
        Sheet sheet = writer.getSheet();
        //excel平均分配列宽
        for (int i=0;i<colums.size();i++) {
            Integer max = i;
            Integer maxLength = convers.stream().map(li -> {
                String str = Convert.convert(String.class, li.get(max));
                return ObjectUtil.isNull(str)?0:str.length();
            }).max((o1, o2) ->o1.compareTo(o2)).get();
            sheet.setColumnWidth(i,(maxLength + 16) * 256 >6000?6000:(maxLength + 10) * 256);

            //单元格样式，头部
            CellStyle cellStyle = writer.getHeadCellStyle();
            cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Row row = sheet.getRow(0);
            Cell cell = row.getCell(i);
            cell.setCellStyle(cellStyle);
        }

        // 关闭writer，释放内存
        writer.close();

        return file;
    }

    /**
     * excel 导出
     * @param list 导出数据
     * @param key  excel导出的列名，已经对应的key -> "name:姓名,age:年龄"
     * @return
     */
    public static File export(List<Record> list, String key, File file) {
        return export(list, key, file,null);
    }


    /**
     * entity 导出
     * 必须设置 public static final String EXCEL_EXPORT_KEY = "name:姓名，age:年龄"
     * @param list 导出数据
     * @param <T> model
     * @return
     */
    public static <T extends Model> File export(List<T> list, File file, BiFunction<Record,String,String> function) {
        if (list.isEmpty()) {
            return file;
        }
        String key = "";
        //获取 excel_export_key
        try {
            Class<? extends Model> clazz = list.get(0).getClass();
            Field excelExportKey = ReflectUtil.getField(clazz, "EXCEL_EXPORT_KEY");
            key = Convert.convert(String.class, excelExportKey.get(clazz));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new MyBaselogicException("999", "excel导出异常，获取EXCEL_EXPORT_KEY异常");
        }
        if (StrKit.isBlank(key)) {
            throw new MyBaselogicException("999", "excel导出异常，model中EXCEL_EXPORT_KEY不能为空");
        }
        //model -> record
        try {
            //获取头部信息
            List<String> cloms = FunctionUtils.convers(CommonUtil.splitStr(key, ","), str -> CommonUtil.splitStr4Temp(str, "{}:{}").get(0));
            List<Record> convers = FunctionUtils.convers(list, m -> {
                Record record = new Record();
                cloms.forEach(c -> record.set(c, m.get(c)));
                return record;
            });
            return export(convers, key, file, function);
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyBaselogicException("999", "excel导出失败");
        }
    }

    /**
     * entity 导出
     * @param list
     * @param file
     * @param <T>
     * @return
     */
    public static <T extends Model> File export(List<T> list, File file) {
        return export(list, file, null);
    }

    /**
     * map转 record
     * @param list list
     * @return
     */
    public static List<Record> map2Record(List<Map> list){
        //map -> record
        List<Record> convers = FunctionUtils.convers(list, map -> {
            Record record = new Record();
            map.forEach((k, v) -> record.set(Convert.convert(String.class,k), v));
            return record;
        });
        return convers;
    }

    /**
     * entity 转 record
     * @param list list
     * @param <T>
     * @return
     */
    public static <T extends Model> List<Record> entity2Record(List<T> list){
        String json = JsonKit.toJson(list);

        //json -> map
        List<Map> mapList = JSON.parseArray(json, Map.class);
        return map2Record(mapList);
    }
}
